Skip to content

feat: support socks5 and tun modes#364

Open
xvzc wants to merge 39 commits intomainfrom
feat/support-socks5
Open

feat: support socks5 and tun modes#364
xvzc wants to merge 39 commits intomainfrom
feat/support-socks5

Conversation

@xvzc
Copy link
Owner

@xvzc xvzc commented Mar 18, 2026

No description provided.

xvzc added 15 commits December 22, 2025 00:44
- Merge bind_*.go and gateway_*.go into unified netutil_*.go files
- netutil_bsd.go: bindToInterface (IP_BOUND_IF) + getDefaultGateway for macOS/BSD
- netutil_linux.go: bindToInterface (LocalAddr) + getDefaultGateway for Linux
- netutil.go: no-op fallbacks for unsupported platforms
- Simplify bindToInterface on BSD to only use iface.Index
- Reduces file count from 6 to 3
- Replace 0.0.0.0/32 hack with proper -ifscope default route
- SetGatewayRoute now uses 'route add -ifscope <iface> default <gateway>'
- This creates a scoped default route for IP_BOUND_IF sockets
- UnsetGatewayRoute updated to clean up ifscope routes properly
- More logical and standards-compliant routing approach
- Better reflects the semantics: deadline extends on activity
- Updated comments to clarify idle-based timeout behavior
- Connection stays alive as long as there are Read/Write operations
- ConnOptions.UDPTimeout -> ConnOptions.UDPIdleTimeout
- CLI flag: --udp-timeout -> --udp-idle-timeout
- TOML key: udp-timeout -> udp-idle-timeout
- Updated all usages across codebase and tests
- Clearer naming to indicate idle-based timeout behavior
@github-actions github-actions bot added the feature New features label Mar 18, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors SpoofDPI’s proxy architecture into a unified server.Server interface, expands functionality (SOCKS5 incl. UDP ASSOCIATE + TUN UDP/TCP handling), and updates configuration/schema + docs to match the new “app/connection/udp” option model.

Changes:

  • Introduces internal/server/* implementations (HTTP, SOCKS5, TUN) and moves startup/shutdown to server.Server.
  • Adds UDP support across layers: UDP desyncer, UDP packet writer/sniffer, UDP tunneling/connection pooling, and platform routing helpers.
  • Migrates config structure (general/serverapp/connection, adds [udp]), updates DNS/resolver plumbing, and refreshes MkDocs user-guide navigation/content.

Reviewed changes

Copilot reviewed 85 out of 86 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mkdocs.yml Updates documentation nav for new option sections (App/Connection/UDP).
internal/system/sysproxy.go Removes old system proxy stub (moved to per-server network config).
internal/system/sysproxy_linux.go Removes old Linux proxy stub.
internal/system/sysproxy_darwin.go Removes old macOS proxy implementation (replaced by PAC-based per-server setup).
internal/session/session.go Updates trace ID generation and defaulting behavior.
internal/server/tun/udp.go Adds UDP tunneling handler for TUN mode (pool + idle timeout + UDP desync).
internal/server/tun/tcp.go Adds TCP/TLS handler for TUN mode (SNI extraction + rule matching + tunneling).
internal/server/tun/network.go Adds no-op routing helpers for unsupported OSes.
internal/server/tun/network_linux.go Implements Linux route/interface/policy-routing helpers for TUN.
internal/server/tun/network_bsd.go Implements BSD/macOS route/interface helpers for TUN.
internal/server/socks5/udp_associate.go Implements SOCKS5 UDP ASSOCIATE relay logic (client↔target UDP).
internal/server/socks5/server.go Adds SOCKS5 server implementing server.Server.
internal/server/socks5/network.go Adds non-darwin system proxy no-op for SOCKS5 mode.
internal/server/socks5/network_darwin.go Adds macOS PAC-based system proxy setup for SOCKS5 mode.
internal/server/socks5/connect.go Implements SOCKS5 CONNECT handling (TCP + TLS desync when applicable).
internal/server/socks5/bind.go Implements SOCKS5 BIND handling.
internal/server/server.go Introduces common server.Server interface (Start/Stop/Addr/network config).
internal/server/http/server.go Refactors HTTP proxy into server.Server (Start/Stop + network config hooks).
internal/server/http/network.go Adds non-darwin system proxy no-op for HTTP mode.
internal/server/http/network_darwin.go Adds macOS PAC-based system proxy setup for HTTP mode.
internal/server/http/https.go Refactors HTTPS CONNECT handling + tunnels via new netutil tunnel helpers.
internal/server/http/http.go Refactors HTTP forwarding + tunnels via new netutil tunnel helpers.
internal/proxy/socks5/socks5_proxy.go Removes legacy SOCKS5 proxy implementation (replaced by internal/server/socks5).
internal/proxy/proxy.go Removes legacy proxy interface.
internal/proto/socks5.go Renames SOCKS5 constants/types and expands request fields (ATYP/FQDN).
internal/proto/http.go Renames ExtractDomainExtractHost.
internal/packet/udp_writer.go Adds UDP packet injector (crafted UDP packets).
internal/packet/udp_sniffer.go Adds UDP sniffer for hop/TTL estimation.
internal/packet/tcp_writer.go Adjusts Ethernet header emission logic for TCP writer.
internal/packet/tcp_sniffer.go Updates TCP sniffer: cache keys, local filtering, linktype-aware BPF.
internal/packet/sniffer.go Updates sniffer interface + adds shared hop estimation/local-IP helpers.
internal/packet/network_detector.go Improves gateway/interface detection + adds periodic probing.
internal/packet/LICENSE Removes vendored license file from internal/packet.
internal/packet/handle_linux.go Improves Linux LinkType detection (Ethernet vs Raw vs SLL).
internal/netutil/pac.go Adds local PAC server helper for macOS network proxy configuration.
internal/netutil/netutil.go Adds non-linux/darwin/freebsd stubs for interface binding + gateway detection.
internal/netutil/netutil_linux.go Adds Linux interface-binding + default-gateway detection.
internal/netutil/netutil_bsd.go Adds BSD/macOS interface-binding + default-gateway detection.
internal/netutil/dial.go Refactors DialFastest to accept a Destination (addrs/port/timeout/iface).
internal/netutil/conn.go Refactors tunneling helpers (directional results + WaitAndLogTunnel + conn wrappers).
internal/netutil/conn_pool.go Adds UDP connection pool (LRU + idle timeout cleanup).
internal/netutil/addr.go Introduces Destination + adds subnet selection + default iface/gateway utilities.
internal/matcher/matcher.go Switches pointer helpers to lo and updates priority comparison.
internal/matcher/matcher_test.go Updates tests to use lo pointers.
internal/matcher/domain.go Updates defaults for rule fields using lo.
internal/matcher/domain_test.go Updates tests to use lo pointers.
internal/matcher/addr.go Updates defaults for rule fields using lo.
internal/matcher/addr_test.go Updates tests to use lo pointers.
internal/logging/logging.go Adjusts trace-id logging behavior + renames joined-error logging helpers.
internal/dns/udp.go Adds conn timeout wiring into UDP resolver and renames defaults.
internal/dns/system.go Renames System resolver type + switches to LookupIP and net.IP slices.
internal/dns/route.go Updates routing resolver to net.IP + improves logging and error handling.
internal/dns/resolver.go Switches RecordSet to []net.IP and joins resolver errors via errors.Join.
internal/dns/https.go Refactors DoH to POST + http2 transport + retry handling.
internal/dns/cache.go Updates cache logging granularity/fields.
internal/dns/addrselect/addrselect.go Refactors RFC6724 sorter to []net.IP (drops Zone handling).
internal/desync/udp.go Adds UDP desyncer (fake packet injection based on hop/TTL).
internal/config/validate.go Updates validator enums for new app/connection/segment option sets.
internal/config/validate_test.go Adds/updates validation tests (incl. log-level coverage).
internal/config/toml.go Switches pointer helper to lo.
internal/config/toml_test.go Updates TOML fixtures to new [app]/[connection]/[udp] schema.
internal/config/segment_test.go Adds placeholder segment test file.
internal/config/parse.go Adds parsing for app mode + segment-from + custom split mode.
internal/config/config.go Restructures config model and defaulting; adds UDP + pcap enablement checks.
internal/config/config_test.go Updates tests for config reshape + UDP defaults.
internal/config/cli_test.go Updates CLI tests for renamed flags/options and UDP flags.
internal/cache/ttl_cache.go Adds Range and Size helpers.
internal/cache/lru_cache.go Adds Range/Delete/Size helpers.
internal/cache/cache.go Extends cache interface with Delete/Range/Size.
cmd/spoofdpi/main_test.go Updates main tests for new config shape and server creation.
go.mod Adds dependencies (water, x/net, gvisor, lo, etc.) and bumps x/* versions.
go.sum Updates dependency checksums accordingly.
docs/user-guide/udp.md Adds UDP configuration documentation.
docs/user-guide/server.md Removes old server configuration doc (replaced by app/connection).
docs/user-guide/policy.md Removes policy auto section; reframes template behavior.
docs/user-guide/overview.md Updates overview for new option categories and examples.
docs/user-guide/https.md Documents custom split-mode and new defaults.
docs/user-guide/connection.md Adds connection timeout + fake TTL documentation.
docs/user-guide/app.md Replaces “General” page with “App” page and new flag names.

Comment on lines +61 to +86
func (p *ConnPool) Add(key string, rawConn net.Conn) *PooledConn {
p.mu.Lock()
defer p.mu.Unlock()

// Evict if capacity is reached
if p.ll.Len() >= p.capacity {
p.evictOldest()
}

now := time.Now()
expiredAt := now.Add(p.timeout)

wrapper := &PooledConn{
Conn: rawConn,
pool: p,
key: key,
timeout: p.timeout,
expiredAt: expiredAt,
}

_ = rawConn.SetDeadline(expiredAt)

elem := p.ll.PushFront(&connEntry{key: key, conn: wrapper})
p.cache[key] = elem

return wrapper
Comment on lines +141 to +184
rawConn, err := netutil.DialFastest(ctx, "udp", dst)
if err != nil {
logger.Warn().Err(err).Str("addr", targetAddrStr).Msg("failed to dial udp target")
continue
}

// Add to pool (pool handles LRU eviction and deadline)
conn := h.pool.Add(key, rawConn)

// Apply UDP options from rule if matched
udpOpts := h.defaultUDPOpts.Clone()
if rule != nil && rule.UDP != nil {
udpOpts = udpOpts.Merge(rule.UDP)
}

// Send fake packets before real payload (UDP desync)
if h.desyncer != nil {
_, _ = h.desyncer.Desync(ctx, lNewConn, conn.Conn, udpOpts)
}

// Start a goroutine to read from the target and forward to the client
go func(targetConn *netutil.PooledConn, clientAddr *net.UDPAddr) {
respBuf := make([]byte, 65535)
for {
n, _, err := targetConn.Conn.(*net.UDPConn).ReadFromUDP(respBuf)
if err != nil {
// Connection closed or network issues
return
}

// Inbound: Target -> Proxy -> Client
// Wrap with SOCKS5 Header
remoteAddr := targetConn.Conn.(*net.UDPConn).RemoteAddr().(*net.UDPAddr)
header := createUDPHeaderFromAddr(remoteAddr)
response := append(header, respBuf[:n]...)

if _, err := lNewConn.WriteToUDP(response, clientAddr); err != nil {
// If we can't write back to the client, it might be gone or network issue.
// Exit this goroutine to avoid busy looping.
logger.Warn().Err(err).Msg("failed to write udp to client")
return
}
}
}(conn, clientAddr)
Comment on lines +175 to +188
} else {
// Check IP Version == 4 at the base offset
// Load byte at baseOffset, mask 0xF0, check if 0x40
instructions = append(
instructions,
// BPFInstruction{Op: 0x30, Jt: 0, Jf: 0, K: baseOffset}, // Ldb [baseOffset]
BPFInstruction{Op: 0x54, Jt: 0, Jf: 0, K: 0xf0}, // And 0xf0
BPFInstruction{
Op: 0x15,
Jt: 0,
Jf: 8,
K: 0x40,
}, // Jeq 0x40, True, False(Skip to End)
)
Comment on lines +78 to +86
packetLayers, err = uw.createIPv6Layers(
srcMAC,
dstMAC,
srcUDP.IP,
srcUDP.IP,
srcPort,
dstPort,
ttl,
)
Comment on lines +49 to +53
// Configure HTTP/2 transport explicitly
if err := http2.ConfigureTransport(tr); err != nil {
// Log error instead of panic if strict http2 is not required, otherwise panic
panic(fmt.Sprintf("failed to configure http2: %v", err))
}
Comment on lines +26 to +35
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok {
// Match IP version: use IPv4 source for IPv4 target, IPv6 for IPv6
if targetIP.To4() != nil && ipnet.IP.To4() != nil && !ipnet.IP.IsLoopback() {
dialer.LocalAddr = &net.TCPAddr{IP: ipnet.IP}
return nil
} else if targetIP.To4() == nil && ipnet.IP.To4() == nil && !ipnet.IP.IsLoopback() {
dialer.LocalAddr = &net.TCPAddr{IP: ipnet.IP}
return nil
}
@xvzc xvzc requested a review from Copilot March 18, 2026 21:29
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new runtime modes (SOCKS5 and TUN) and refactors networking/config plumbing to support UDP handling, system network configuration, and packet-based desync features across modes.

Changes:

  • Introduces a unified server.Server interface and implements SOCKS5 proxy mode plus TUN TCP/UDP handlers.
  • Refactors config layout into [app], [connection], and [udp], updates CLI/tests/docs accordingly, and modernizes DNS/connection dialing around netutil.Destination.
  • Expands packet tooling (UDP sniffer/writer, routing helpers, session cache, tunnel accounting) to support UDP desync and TUN routing.

Reviewed changes

Copilot reviewed 90 out of 91 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mkdocs.yml Updates docs navigation for new option sections (App/Connection/UDP).
internal/system/sysproxy.go Removes legacy system proxy stubs.
internal/system/sysproxy_linux.go Removes legacy Linux system proxy stub.
internal/system/sysproxy_darwin.go Removes legacy macOS system proxy implementation (moved per-server).
internal/session/session.go Adjusts trace ID generation/lookup implementation.
internal/server/tun/udp.go Adds UDP handler for TUN mode with rule-based options and tunneling.
internal/server/tun/tcp.go Adds TCP(+TLS sniff/SNI match) handler for TUN mode.
internal/server/tun/network.go Adds unsupported-platform no-op routing/address helpers.
internal/server/tun/network_linux.go Adds Linux route/interface/gateway policy routing helpers.
internal/server/tun/network_bsd.go Adds macOS/FreeBSD route/interface/gateway helpers.
internal/server/socks5/udp_associate.go Implements SOCKS5 UDP ASSOCIATE relay with NAT session pooling + UDP desync.
internal/server/socks5/server.go Implements SOCKS5 server (accept loop, negotiation, command dispatch, net config).
internal/server/socks5/network.go Adds non-darwin no-op system proxy hooks for SOCKS5 mode.
internal/server/socks5/network_darwin.go Adds macOS PAC-based system proxy setup for SOCKS5 mode.
internal/server/socks5/connect.go Implements SOCKS5 CONNECT handling with TLS-aware desync path.
internal/server/socks5/bind.go Implements SOCKS5 BIND handling.
internal/server/server.go Introduces new core Server interface.
internal/server/http/server.go Migrates HTTP proxy to server.Server and new config layout; updates dialing/matching.
internal/server/http/network.go Adds non-darwin no-op system proxy hooks for HTTP mode.
internal/server/http/network_darwin.go Adds macOS PAC-based system proxy setup for HTTP mode.
internal/server/http/https.go Refactors HTTPS handler to use new destination/conn options and tunnel aggregation.
internal/server/http/http.go Refactors HTTP handler to use new destination type and shared tunnel aggregation.
internal/proxy/proxy.go Removes legacy ProxyServer interface.
internal/proto/socks5.go Expands SOCKS5 protocol parsing/types/constants.
internal/proto/http.go Renames ExtractDomain to ExtractHost.
internal/packet/udp_writer.go Adds UDP packet crafting/injection support.
internal/packet/udp_sniffer.go Adds UDP packet sniffing + hop/TTL estimation updates.
internal/packet/tcp_writer.go Adjusts Ethernet header emission for IPv4 crafted packets.
internal/packet/sniffer.go Updates sniffer interface and adds hop estimation/local-IP helpers.
internal/packet/network_detector.go Refactors network detection/probing and default interface selection.
internal/packet/LICENSE Removes embedded Apache 2.0 license file from packet dir.
internal/packet/handle_linux.go Improves Linux link-type detection (SLL vs Ethernet vs raw IP).
internal/netutil/session_cache.go Adds NAT-keyed session cache with LRU + idle/cleanup behavior.
internal/netutil/route.go Adds safe subnet selection and default iface/gateway discovery helpers.
internal/netutil/route_unsupported.go Adds unsupported-platform stubs for routing helpers.
internal/netutil/route_linux.go Adds Linux bind-to-interface and default gateway discovery.
internal/netutil/route_bsd.go Adds BSD bind-to-interface and default gateway discovery.
internal/netutil/pac.go Adds local PAC HTTP server helper.
internal/netutil/netutil.go Adds IPv4-mapped detection helper used by key types.
internal/netutil/key.go Adds zero-allocation NAT/IP cache keys.
internal/netutil/key_benchmark_test.go Adds benchmark for NAT key allocation changes.
internal/netutil/dst.go Introduces Destination struct and updates destination validation.
internal/netutil/dial.go Refactors dialing to accept Destination (timeouts + iface binding).
internal/netutil/conn.go Refactors tunneling to report transfer results + adds buffered/idle-timeout conn wrappers.
internal/matcher/matcher.go Replaces internal ptr helper usage with lo in priority comparisons.
internal/matcher/matcher_test.go Updates matcher tests to use lo pointers.
internal/matcher/domain.go Updates defaulting logic to use lo pointers.
internal/matcher/domain_test.go Updates domain matcher tests to use lo pointers.
internal/matcher/addr.go Updates defaulting logic to use lo pointers.
internal/matcher/addr_test.go Updates addr matcher tests to use lo pointers.
internal/logging/logging.go Ensures trace_id is always logged; renames unwrapped error helpers.
internal/dns/udp.go Adds conn-timeout integration into UDP resolver.
internal/dns/system.go Renames system resolver + switches to LookupIP returning net.IP.
internal/dns/route.go Refactors routing resolver to net.IP and improves logging/metrics.
internal/dns/resolver.go Switches DNS record set to net.IP and joins multi-errors via errors.Join.
internal/dns/https.go Refactors DoH transport (HTTP/2) and changes exchange to POST with retries.
internal/dns/cache.go Updates cache resolver to generic cache interface and new method names.
internal/dns/addrselect/addrselect.go Refactors RFC6724 selection to operate on net.IP.
internal/desync/udp.go Adds UDP desyncer implementation using writer/sniffer TTL data.
internal/config/validate.go Updates validators for new app/connection/udp option enums.
internal/config/validate_test.go Updates tests and adds log-level validator test.
internal/config/toml.go Switches ptr helper to lo.ToPtr.
internal/config/toml_test.go Updates config parsing tests to new app/connection/udp structure.
internal/config/segment_test.go Adds placeholder test file for segment package/tests.
internal/config/parse.go Adds parsing for app mode, custom HTTPS split mode, and segment-from type.
internal/config/config.go Major config schema refactor (App/Conn/UDP) + updates pcap-enable logic and defaults.
internal/config/config_test.go Updates config tests for schema refactor and UDP defaults.
internal/config/cli_test.go Updates CLI tests for new flags/options and SOCKS5 default port behavior.
internal/cache/ttl_cache.go Refactors TTL cache to be generic and expands API surface.
internal/cache/ttl_cache_benchmark_test.go Adds benchmark comparing string vs struct keys.
internal/cache/lru_cache.go Refactors LRU cache to be generic and expands API surface.
internal/cache/cache.go Updates cache interface to generic Fetch/Store/Evict/ForEach/Size.
go.sum Updates dependency checksums and adds new deps.
go.mod Adds new dependencies (lo, water, x/net, gvisor) and bumps x/* deps.
docs/user-guide/udp.md Adds UDP configuration documentation.
docs/user-guide/server.md Removes legacy server options documentation (superseded by app/connection).
docs/user-guide/policy.md Removes policy.auto docs and reframes template behavior.
docs/user-guide/overview.md Updates overview to reflect new option sections and examples.
docs/user-guide/https.md Updates HTTPS docs (chunk default, fake-packet format, custom segments).
docs/user-guide/connection.md Adds connection (timeouts/default-fake-ttl) documentation.
docs/user-guide/app.md Replaces “General” docs with “App” docs (mode/network-config/etc.).
cmd/spoofdpi/main_test.go Updates main tests for new config schema and server creation.

Comment on lines +49 to +53
// Configure HTTP/2 transport explicitly
if err := http2.ConfigureTransport(tr); err != nil {
// Log error instead of panic if strict http2 is not required, otherwise panic
panic(fmt.Sprintf("failed to configure http2: %v", err))
}
Comment on lines +81 to +85
done := make(chan struct{})
go func() {
_, _ = io.Copy(io.Discard, lConn) // Block until TCP closes
close(done)
}()
Comment on lines +106 to +114
// Initial Client Identification
if clientAddr == nil {
clientAddr = addr
}

// Only accept packets from the client that established the association
if !addr.IP.Equal(clientAddr.IP) || addr.Port != clientAddr.Port {
continue
}
Comment on lines +170 to +176
eth := &layers.Ethernet{
SrcMAC: srcMAC,
DstMAC: dstMAC,
EthernetType: layers.EthernetTypeIPv6,
}
packetLayers = append(packetLayers, eth)

Comment on lines 127 to 134
if srcMAC != nil {
eth := &layers.Ethernet{
SrcMAC: srcMAC,
DstMAC: dstMAC,
EthernetType: layers.EthernetTypeIPv4,
}
packetLayers = append(packetLayers, eth)
}
Comment on lines +96 to +101
func (p *SOCKS5Proxy) Stop() error {
if p.listener != nil {
return p.listener.Close()
}
return nil
}
@xvzc xvzc requested a review from Copilot March 19, 2026 02:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands SpoofDPI to support additional operating modes (SOCKS5 and TUN), along with related networking/routing setup and documentation updates.

Changes:

  • Add TUN-mode TCP/UDP handlers and OS-specific route/interface configuration helpers.
  • Update session trace ID generation/handling.
  • Update docs navigation to reflect the new configuration sections/pages.

Reviewed changes

Copilot reviewed 90 out of 91 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
mkdocs.yml Updates the documentation nav to new “App/Connection/UDP” sections.
internal/system/sysproxy.go Removes legacy non-darwin/non-linux system proxy stub.
internal/system/sysproxy_linux.go Removes legacy Linux system proxy stub implementation.
internal/system/sysproxy_darwin.go Removes legacy macOS system proxy implementation.
internal/session/session.go Changes trace ID generation and default trace ID fallback behavior.
internal/server/tun/tcp.go Introduces TUN TCP handler with TLS SNI extraction + rule matching + tunneling.
internal/server/tun/udp.go Introduces TUN UDP handler with rule application + tunneling.
internal/server/tun/network.go Adds no-op route/interface helpers for unsupported OS builds.
internal/server/tun/network_linux.go Adds Linux routing/policy-routing and interface address configuration via ip.
internal/server/tun/network_bsd.go Adds darwin/freebsd route/interface configuration helpers.
internal/cache/lru_cache.go Updates LRU cache behavior used by connection/session caching.
internal/netutil/session_cache.go Updates session cache storage/eviction behavior for connection reuse.
internal/server/socks5/udp_associate.go Adds/updates SOCKS5 UDP ASSOCIATE handling.
internal/packet/tcp_writer.go Adjusts crafted TCP packet layer building (Ethernet encapsulation logic).
Comments suppressed due to low confidence (1)

internal/cache/lru_cache.go:114

  • LRUCache.Store overwrites an existing entry's value without calling onInvalidate for the old value. This can leak resources when values own file descriptors/sockets (e.g., SessionCache stores *IdleTimeoutConn and relies on onInvalidate to close underlying conns). Consider capturing the old value and invoking onInvalidate (or explicitly evicting first) before replacing entry.value.
	if ok {
		entry := element.Value.(*lruEntry[K])
		entry.value = value

		c.list.MoveToFront(element)
		return true

xvzc added 6 commits March 19, 2026 14:47
LRUCache previously overwrote existing values without notification when
storing a duplicate key. To prevent potential resource leaks, the
onInvalidate callback is now invoked prior to storing the new value,
ensuring the previous entry is properly cleaned up.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds new operating modes (SOCKS5 proxy and TUN transparent mode) and refactors the runtime/config/networking layers to support TCP+UDP handling, per-mode system network configuration, and UDP desync/packet-crafting capabilities.

Changes:

  • Introduces server.Server abstraction and adds SOCKS5 + TUN servers/handlers (including UDP tunneling/desync).
  • Refactors configuration schema into app, connection, and udp sections; updates CLI parsing and docs accordingly.
  • Extends packet/netutil/cache infrastructure (routing helpers, conn registry, generic caches, PAC server support).

Reviewed changes

Copilot reviewed 88 out of 89 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
mkdocs.yml Updates docs navigation for new config sections.
internal/system/sysproxy.go Removes prior system proxy implementation (moved to per-server network config).
internal/system/sysproxy_linux.go Removes Linux no-op/placeholder system proxy implementation.
internal/system/sysproxy_darwin.go Removes previous macOS system proxy implementation (replaced by PAC-based per-mode setup).
internal/session/session.go Removes unsafe trace-id generation and adjusts trace-id fallback behavior.
internal/server/tun/udp.go Adds UDP handler for TUN mode with rule merge + idle timeout + tunneling.
internal/server/tun/tcp.go Adds TCP/TLS handler for TUN mode (SNI extraction + rule matching + desync + tunneling).
internal/server/tun/network.go Adds unsupported-platform stubs for TUN route/interface operations.
internal/server/tun/network_linux.go Implements Linux route/interface/policy-routing helpers for TUN.
internal/server/tun/network_bsd.go Implements darwin/freebsd route/interface helpers for TUN.
internal/server/socks5/server.go Adds SOCKS5 server with CONNECT/BIND/UDP_ASSOCIATE support and rule matching.
internal/server/socks5/network.go Adds non-darwin no-op system proxy setup for SOCKS5 mode.
internal/server/socks5/network_darwin.go Adds PAC-based system proxy setup for SOCKS5 mode on macOS.
internal/server/socks5/connect.go Implements SOCKS5 CONNECT handling (TLS detection + desync + tunneling).
internal/server/socks5/bind.go Implements SOCKS5 BIND handling with bidirectional tunneling.
internal/server/server.go Introduces shared server.Server interface (Listen/SetNetworkConfig/etc.).
internal/server/http/server.go Refactors HTTP proxy to implement server.Server and to use new config types.
internal/server/http/network.go Adds non-darwin no-op system proxy setup for HTTP mode.
internal/server/http/network_darwin.go Adds PAC-based system proxy setup for HTTP mode on macOS.
internal/server/http/https.go Refactors HTTPS CONNECT handling + tunnel aggregation + uses new conn options.
internal/server/http/http.go Refactors plain HTTP tunneling to new tunnel result aggregation.
internal/proxy/socks5/socks5_proxy.go Removes old SOCKS5 proxy implementation (replaced by internal/server/socks5).
internal/proxy/proxy.go Removes old proxy interface (superseded by internal/server/server.go).
internal/proto/socks5.go Updates SOCKS5 constants/struct layout and parsing fields (ATYP/FQDN/etc.).
internal/proto/http.go Renames ExtractDomain to ExtractHost.
internal/packet/udp_writer.go Adds UDP packet crafting/injection support.
internal/packet/udp_sniffer.go Adds UDP TTL/hop-count sniffer + BPF filter generation.
internal/packet/tcp_writer.go Makes Ethernet header optional depending on link type/MAC availability.
internal/packet/sniffer.go Updates sniffer interface/types and adds hop-estimation helpers.
internal/packet/network_detector.go Improves gateway/interface detection and adds periodic probing.
internal/packet/LICENSE Removes embedded license file from packet directory.
internal/packet/handle_linux.go Improves Linux link-type detection (Ethernet vs Raw vs SLL).
internal/netutil/route.go Adds route utilities (safe subnet + default iface/gateway discovery).
internal/netutil/route_unsupported.go Adds unsupported-platform stubs for routing helpers.
internal/netutil/route_linux.go Adds Linux gateway parsing + interface binding support.
internal/netutil/route_bsd.go Adds BSD/macOS gateway parsing + IP_BOUND_IF binding support.
internal/netutil/pac.go Adds PAC server helper used by macOS system proxy setup.
internal/netutil/netutil.go Adds helper for IPv4-mapped IPv6 detection.
internal/netutil/key.go Adds zero-allocation cache keys (NATKey/IPKey).
internal/netutil/dst.go Introduces Destination struct and updates destination validation types.
internal/netutil/dial.go Refactors dialing to accept *Destination and support interface binding.
internal/netutil/conn.go Refactors tunnel copy + introduces aggregated transfer results and idle-timeout conn.
internal/netutil/conn_registry.go Adds LRU+idle-timeout UDP connection registry/pool.
internal/matcher/matcher.go Switches pointer helpers to lo and keeps priority comparison logic.
internal/matcher/matcher_test.go Updates tests for lo pointer helpers.
internal/matcher/domain.go Updates defaults to lo pointer helpers.
internal/matcher/domain_test.go Updates tests for lo pointer helpers.
internal/matcher/addr.go Updates defaults to lo pointer helpers.
internal/matcher/addr_test.go Updates tests for lo pointer helpers.
internal/logging/logging.go Adjusts trace-id logging behavior and renames unwrapped-error helpers.
internal/dns/udp.go Wires DNS timeouts via connection options.
internal/dns/system.go Refactors system resolver to use LookupIP and []net.IP.
internal/dns/route.go Refactors routing resolver to new DNS/IP types and adds timing logs.
internal/dns/resolver.go Switches DNS record sets to []net.IP and joins errors.
internal/dns/https.go Refactors DoH transport (timeouts/http2) and changes request style + retry logic.
internal/dns/cache.go Migrates DNS cache to generic cache interface and updates logging/ops.
internal/dns/addrselect/addrselect.go Migrates address selection helpers to []net.IP.
internal/desync/udp.go Adds UDP desync logic (fake packet injection) using UDP sniffer/writer.
internal/config/validate.go Updates validation enums for new config schema.
internal/config/validate_test.go Updates validation tests and adds log-level tests.
internal/config/toml.go Switches pointer helper to lo.
internal/config/toml_test.go Updates TOML schema tests for new config sections/options.
internal/config/segment_test.go Adds placeholder test file for segment-related package.
internal/config/parse.go Adds parsing for new enums (app mode, custom split mode, segment-from).
internal/config/config.go Refactors config structure (App/Conn/UDP) and PCAP enablement logic.
internal/config/config_test.go Updates tests for new config schema/UDP defaults.
internal/config/cli_test.go Updates CLI tests for new flags/config layout.
internal/cache/ttl_cache.go Makes TTL cache generic and expands cache interface support.
internal/cache/lru_cache.go Makes LRU cache generic, adds eviction hooks and richer interface methods.
internal/cache/cache.go Updates cache interface to be generic and adds iteration/eviction APIs.
go.sum Updates dependency checksums for added/updated modules.
go.mod Adds new dependencies for new modes/features (lo, water, x/net, gvisor, etc.).
docs/user-guide/udp.md Adds UDP configuration documentation.
docs/user-guide/server.md Removes old server configuration doc (replaced by app/connection docs).
docs/user-guide/policy.md Updates policy docs to reflect template-only approach.
docs/user-guide/overview.md Updates docs overview for new config categories and examples.
docs/user-guide/https.md Documents new defaults and custom segment plans.
docs/user-guide/connection.md Adds connection timeouts + default-fake-ttl documentation.
docs/user-guide/app.md Replaces general config doc with app-mode/listen-addr/network auto-config docs.
cmd/spoofdpi/main_test.go Updates main tests for new config schema and server creation.

Comment on lines +39 to +43
pacURL, l, err := netutil.RunPACServer(pacContent)
if err != nil {
return fmt.Errorf("error creating pac server: %w", err)
}
pacListener = l
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetSystemProxy assigns to the package-level pacListener without closing any existing listener first. If SetSystemProxy is invoked more than once in-process, the previous PAC server listener can be leaked. Consider closing an existing pacListener (if non-nil) before starting a new PAC server, or make the operation idempotent.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 88 out of 89 changed files in this pull request and generated 3 comments.

Comment on lines +80 to +95
// 3. Send Success Response
err = proto.SOCKS5SuccessResponse().Bind(net.IPv4zero).Port(0).Write(lConn)
if err != nil {
logger.Error().Err(err).Msg("failed to write socks5 success reply")
return err
}

// logger := logging.WithLocalScope(ctx, h.logger, "connect(tcp)")
dst.Timeout = *connOpts.TCPTimeout

rConn, err := netutil.DialFastest(ctx, "tcp", dst)
if err != nil {
return err
}
defer netutil.CloseConns(rConn)

Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOCKS5 CONNECT sends a success reply to the client before confirming the upstream TCP dial succeeded. If DialFastest fails, the client has already received a success response and may hang or mis-handle the connection. Consider dialing first (or at least verifying dst.Addrs is non-empty and the dial is likely to succeed), then send SOCKS5SuccessResponse only after the upstream connection is established; otherwise send a failure response.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +33
server := &http.Server{
Handler: mux,
}

go func() {
_ = server.Serve(listener)
}()

addr := listener.Addr().(*net.TCPAddr)
url := fmt.Sprintf("http://127.0.0.1:%d/proxy.pac", addr.Port)

return url, listener, nil
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunPACServer starts an http.Server in a goroutine but only returns the net.Listener to callers. Closing the listener does not guarantee active connections and the Serve goroutine are fully terminated, which can leak goroutines/resources across repeated enable/disable cycles. Consider returning a cleanup function (or the *http.Server) so callers can invoke server.Close()/Shutdown in addition to closing the listener.

Copilot uses AI. Check for mistakes.
Comment on lines +184 to +205
go func(rConn *netutil.IdleTimeoutConn, lAddr *net.UDPAddr, remoteAddr *net.UDPAddr) {
respBuf := make([]byte, 65535)
for {
// Read via IdleTimeoutConn so each inbound packet extends the deadline.
n, err := rConn.Read(respBuf)
if err != nil {
// Connection closed or network issues
return
}

// Inbound: Target -> Proxy -> Client
// Wrap with SOCKS5 Header
header := createUDPHeaderFromAddr(remoteAddr)
response := append(header, respBuf[:n]...)

if _, err := lUDPConn.WriteToUDP(response, lAddr); err != nil {
// If we can't write back to the client, it might be gone or network issue.
// Exit this goroutine to avoid busy looping.
logger.Warn().Err(err).Msg("failed to write udp to client")
return
}
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UDP ASSOCIATE spawns a per-session goroutine that returns on read error without closing/evicting the cached connection. This can leave dead connections in the pool until periodic cleanup, and repeated failures can accumulate idle entries. Consider explicitly closing the IdleTimeoutConn (or evicting the NAT key) when the read loop exits due to error to release resources promptly.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants